package gnss_plugs

import (
	"dgo/goutils/utils"
	"fmt"
	"net"
	"sync/atomic"
	"time"
)

type IAsyncTcpProcessor interface {
	OnTcpConnected(sender *AsyncTcpClt)
	OnTcpConnectError(sender *AsyncTcpClt, err error)
	OnTcpRecvBuf(sender *AsyncTcpClt, buf []byte, l int)
	OnTcpMakeRecvBuf() []byte
	OnTcpDisconnected(sender *AsyncTcpClt)
}

/***
 * 异步客户端连接类
 */
type AsyncTcpClt struct {
	instanceid         string
	remoteAddress      string
	processor          IAsyncTcpProcessor
	conn               net.Conn
	connected          bool
	terminated         int32
	closingflag        int32
	runflag            int32         // > 1, 正在运行， 0:停止运行
	disTime            time.Time     // 断线时间
	lastRecvTime       time.Time     // 最后一次接收数据的时间
	reconnectInterval  time.Duration // 重连间隔
	disInfo            string
	recvBytes          int64 // 链接成功后, 接收到的字节数, 连接重新建立,将重置
	sendBytes          int64 // 链接成功后, 接收到的字节数, 连接重新建立,将重置
	state_debug_string string
	DailCb             func(network, addr string) (c net.Conn, err error)
}

func NewAsyncTcpClt(processor IAsyncTcpProcessor) *AsyncTcpClt {
	rval := &AsyncTcpClt{
		instanceid:        utils.RandKeyString(24),
		processor:         processor,
		terminated:        1, // 停止状态
		reconnectInterval: time.Second * 5,
	}
	return rval
}

func (this *AsyncTcpClt) GetDisInfo() string {
	return this.disInfo
}

/***
 * 只在接收线程中调用
 */
func (this *AsyncTcpClt) innerCheckDoConnect() bool {
	if this.terminated == 1 {
		// 发现线程已经停止
		return false
	}

	var conn net.Conn
	var err error
	if this.DailCb != nil {
		conn, err = this.DailCb("tcp", this.remoteAddress)
	} else {
		conn, err = net.Dial("tcp", this.remoteAddress)
	}

	if err != nil {
		this.processor.OnTcpConnectError(this, err)
		return false
	}
	this.conn = conn
	this.connected = true
	this.lastRecvTime = time.Now()
	this.recvBytes = 0
	this.sendBytes = 0
	this.processor.OnTcpConnected(this)
	return true
}

func (this *AsyncTcpClt) LastRecvTime() time.Time {
	return this.lastRecvTime
}

func (this *AsyncTcpClt) Connected() bool {
	return this.connected
}

/***
 * 只在接收线程中调用
 */
func (this *AsyncTcpClt) innerDoClose() {
	if atomic.CompareAndSwapInt32(&this.closingflag, 0, 1) {
		// 确保单线程执行
		defer func() {
			this.closingflag = 0
		}()

		if this.connected {
			this.conn.Close()
			this.processor.OnTcpDisconnected(this)
			this.connected = false
		}
		this.disTime = time.Now()
	}
}

/***
 * 进行一次断线，为了让接收和发送返回异常后可以在接收线程中重新判断当前状态
 */
func (this *AsyncTcpClt) BreakConnect() {
	if this.conn != nil {
		this.conn.Close() // 关闭连接，接收时会出现异常, 进入关闭模式
	}
}

func (this *AsyncTcpClt) Stop() {
	if atomic.CompareAndSwapInt32(&this.terminated, 0, 1) {
		this.BreakConnect()
		i := 0
		for { // 采用循环等待，输出状态
			if this.runflag > 0 {
				i++
				time.Sleep(time.Second)
				if i > 10 {
					utils.Log.Warnf("[%s]关闭(%s)超时,可能已经阻塞,正在等待关闭信号, 当前状态:%s", this.instanceid, this.remoteAddress, this.state_debug_string)
				}
				this.BreakConnect()
			} else {
				break
			}
		}
	}
}

func (this *AsyncTcpClt) Start() {
	if atomic.CompareAndSwapInt32(&this.terminated, 1, 0) {
		utils.GoFunc2(this.handRecv)
	}
}

func (this *AsyncTcpClt) SendBuffer(buf []byte) (int, error) {
	n, err := this.conn.Write(buf)
	this.sendBytes += int64(n)
	return n, err
}

func (this *AsyncTcpClt) handRecv() {
	_connectflag := true
	var buffer []byte = nil
	atomic.AddInt32(&this.runflag, 1)
	defer func() {
		atomic.AddInt32(&this.runflag, -1)
	}()

	for {

		if !this.connected {
			if this.terminated == 1 {
				break
			}

			if this.disTime.IsZero() {
				_connectflag = true
			} else if time.Since(this.disTime) >= this.reconnectInterval {
				_connectflag = true
			} else { // 重连时间没到继续等待
				time.Sleep(time.Second)
				continue
			}

			if _connectflag {
				this.state_debug_string = fmt.Sprintf("[%s]检测连接状态", utils.NowString())
				if this.innerCheckDoConnect() {
					continue
				} else {
					// 重连失败
					time.Sleep(time.Second)
					continue
				}
			}
		}

		buffer = this.processor.OnTcpMakeRecvBuf()
		this.state_debug_string = "等待接收数据"
		n, err := this.conn.Read(buffer)
		if err != nil {
			this.disInfo = fmt.Sprintf("(%s)接收时出现了异常: %v", this.conn.RemoteAddr().String(), err)
			utils.Log.Debugf(this.disInfo)
			this.innerDoClose()

			if this.terminated == 1 {
				break
			} else {
				continue
			}
		} else {
			this.recvBytes += int64(n)
			this.lastRecvTime = time.Now()
			this.state_debug_string = "this.processor.OnTcpRecvBuf处理数据"
			this.processor.OnTcpRecvBuf(this, buffer, n)
		}

	}
}
